package org.feng.support;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.feng.base.controller.BaseController;
import org.feng.entity.SysGenerate;
import org.feng.entity.SysMenu;
import org.feng.service.ISysGenerateService;
import org.feng.service.ISysMenuService;
import org.feng.utils.NameUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.*;

/**
 * 代码生成类
 *
 * @author : FengShuai
 * @since : 2024/6/27 9:24
 */
@Component
@Slf4j
@Data
public class Generate {
    private final String AUTHOR = "FengShuai";
    private final ISysGenerateService sysGenerateService;
    private final ISysMenuService sysMenuService;
    @Value("${spring.datasource.url}")
    private String url;
    @Value("${spring.datasource.username}")
    private String username;
    @Value("${spring.datasource.password}")
    private String password;

    public void execute(SysGenerate sysGenerate) {
        Map<String, Object> map = new HashMap<>(10);
        if (sysGenerate.getMenuId() != null) {
            SysMenu sysMenu = sysMenuService.getById(sysGenerate.getMenuId());
            map.put("authCode", sysMenu.getAuthCode());
        }
        ArrayList<String> superColumns = new ArrayList<>();
        if (sysGenerate.getParent()) {
            Collections.addAll(superColumns, "id", "create_user", "update_user", "create_time", "update_time", "deleted");
        }
        map.put("extends", sysGenerate.getParent());
        FastAutoGenerator.create(url, username, password)
                .globalConfig(builder -> builder
                        .author(AUTHOR)
                        .enableSwagger()
                        .disableOpenDir())
                .packageConfig(builder -> builder
                        .parent(sysGenerate.getPackageName())
                        .moduleName(sysGenerate.getModule()))
                .strategyConfig(builder -> builder
                        .addInclude(sysGenerate.getTableName())
                        .addTablePrefix(sysGenerate.getTablePrefix() == null ? "" : sysGenerate.getTablePrefix())
                        .controllerBuilder()
                        .superClass(BaseController.class)
                        .entityBuilder()
                        .addSuperEntityColumns(superColumns)
                        .mapperBuilder()
                        .enableBaseResultMap())
                .injectionConfig(builder -> builder
                        .customMap(map)
                        .customFile(getTemplateNameAndPath(sysGenerate)))
                .templateEngine(new VelocityTemplateEngine() {
                    @Override
                    protected void outputCustomFile(@NotNull List<CustomFile> customFiles, @NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
                        customFiles.forEach(item -> {
                            File file = new File(item.getFilePath() + item.getFileName());
                            if (!file.getParentFile().exists()) {
                                file.getParentFile().mkdirs();
                            }
                            outputFile(file, objectMap, item.getTemplatePath(), true);
                            log.info("文件路径：{}，生成成功", item.getFilePath() + item.getFileName());
                        });
                    }
                }).execute();
    }

    /**
     * 获取模板名称和路径
     */
    private List<CustomFile> getTemplateNameAndPath(SysGenerate sysGenerate) {
        if (StrUtil.isNotEmpty(sysGenerate.getTablePrefix())) {
            sysGenerate.setTableName(sysGenerate.getTableName().replace(sysGenerate.getTablePrefix(), ""));
        }
        String parentPath = System.getProperty("user.dir");
        StringBuilder filePath = new StringBuilder(parentPath).append(File.separator).append("src\\main\\java").append(File.separator).append(sysGenerate.getPackageName().replace(".", File.separator)).append(File.separator).append(sysGenerate.getModule()).append(File.separator);
        String className = NameUtils.underlineToCamel(sysGenerate.getTableName(), true);
        ArrayList<CustomFile> customFiles = new ArrayList<>();
        CustomFile controllerCustomFile = new CustomFile.Builder().fileName(className + "Controller.java").templatePath("/templates/controller.java.vm").packageName(sysGenerate.getPackageName() + "." + sysGenerate.getModule() + ".controller").filePath(filePath + "controller" + File.separator).build();
        CustomFile serviceCustomFile = new CustomFile.Builder().fileName("I" + className + "Service.java").templatePath("/templates/service.java.vm").packageName(sysGenerate.getPackageName() + "." + sysGenerate.getModule() + ".service").filePath(filePath + "service" + File.separator).build();
        CustomFile serviceImplCustomFile = new CustomFile.Builder().fileName(className + "ServiceImpl.java").templatePath("/templates/serviceImpl.java.vm").packageName(sysGenerate.getPackageName() + "." + sysGenerate.getModule() + ".service.impl").filePath(filePath + "service" + File.separator + "impl" + File.separator).build();
        CustomFile mapperCustomFile = new CustomFile.Builder().fileName(className + "Mapper.java").templatePath("/templates/mapper.java.vm").packageName(sysGenerate.getPackageName() + "." + sysGenerate.getModule() + ".mapper").filePath(filePath + "mapper" + File.separator).build();
        CustomFile mapperXmlCustomFile = new CustomFile.Builder().fileName(className + "Mapper.xml").templatePath("/templates/mapper.xml.vm").packageName(sysGenerate.getPackageName() + "." + sysGenerate.getModule() + ".mapper").filePath(filePath + "mapper" + File.separator).build();
        CustomFile entityCustomFile = new CustomFile.Builder().fileName(className + ".java").templatePath("/templates/entity.java.vm").packageName(sysGenerate.getPackageName() + "." + sysGenerate.getModule() + ".entity").filePath(filePath + "entity" + File.separator).build();
        CustomFile vueCustomFile = new CustomFile.Builder().fileName(className + ".vue").templatePath("/templates/vue.vue.vm").packageName(sysGenerate.getPackageName() + "." + sysGenerate.getModule() + ".vue").filePath(filePath + "vue" + File.separator).build();
        CustomFile apiCustomFile = new CustomFile.Builder().fileName(className + "Api.js").templatePath("/templates/api.js.vm").packageName(sysGenerate.getPackageName() + "." + sysGenerate.getModule() + ".js").filePath(filePath + "js" + File.separator).build();
        customFiles.add(controllerCustomFile);
        customFiles.add(serviceCustomFile);
        customFiles.add(serviceImplCustomFile);
        customFiles.add(mapperCustomFile);
        customFiles.add(mapperXmlCustomFile);
        customFiles.add(entityCustomFile);
        customFiles.add(vueCustomFile);
        customFiles.add(apiCustomFile);
        return customFiles;
    }
}
